﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using MovieModel.Model;
using MovieModel.Search;

namespace MovieBuddy.Views.MovieListView
{
    /// <summary>
    /// Interaction logic for MovieList.xaml
    /// </summary>
    public partial class MovieList : ISearchAcceptor
    {
        
        private Func<Movie, IComparable> orderSelector;
        public MovieList()
        {
            InitializeComponent();
            orderSelector = m => m.Name;
            listView.SelectionChanged += ListViewSelectionChanged;
        }

        void ListViewSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (SelectionChanged != null) SelectionChanged(this, e);
        }

        public event EventHandler<SelectionChangedEventArgs> SelectionChanged;

        public MovieListItem[] SelectedItems
        {
            get 
            {
                return listView.SelectedItems.Cast<MovieListItem>().ToArray();
            }
        }

        public Movie[] SelectedMovies
        {
            get
            {
                return listView.SelectedItems.Cast<MovieListItem>().Select(m => m.Movie).ToArray();
            }
        }

        public Movie SelectedMovie
        {
            get
            {
                if (listView.SelectedItem == null) return null;
                return ((MovieListItem)listView.SelectedItem).Movie;
            }
            set
            {
                for (int i = 0; i < listView.Items.Count; i++)
                {
                    if (((MovieListItem)listView.Items[i]).Movie.Id == value.Id)
                    {
                        listView.SelectedIndex = i;
                        return;
                    }
                }
            }
        }

        public IEnumerable<Movie> Movies
        {
            set
            {
                var newValues = value.OrderBy(i => i.Name, StringComparer.CurrentCultureIgnoreCase).ToList();
                int existingIndex = 0;
                int newIndex = 0;
                while (newIndex < newValues.Count || existingIndex < listView.Items.Count)
                {
                    var existingItem = (MovieListItem)(listView.Items.Count <= existingIndex ? null : listView.Items[existingIndex]);
                    Movie newItem = newValues.Count <= newIndex ? null : newValues[newIndex];

                    if (newItem == null)
                    {
                        // we have run out of new items, thus this one can't be in that list
                        listView.Items.RemoveAt(existingIndex);
                        // since we removed an item, no need to increment existing index.
                        continue;
                    }
                    if (existingItem == null)
                    {
                        // we have run out of existing items, so add to the end
                        listView.Items.Add(new MovieListItem(newItem));
                        newIndex++;
                        existingIndex++;
                        continue;
                    }

                    int compare = string.Compare(newItem.Name, existingItem.Movie.Name, StringComparison.CurrentCultureIgnoreCase);
                    if (compare < 0)
                    {
                        // insert new item into existing item
                        listView.Items.Insert(existingIndex, new MovieListItem(newItem));
                        existingIndex++;
                        newIndex++;
                    }
                    else if (compare > 0)
                    {
                        // remove existing item
                        listView.Items.RemoveAt(existingIndex);
                    }
                    else // compare == 0
                    {
                        // item exists, leave it and increment both
                        existingIndex++;
                        newIndex++;
                    }
                }
            }
            get { return listView.Items.Cast<MovieListItem>().Select(i => i.Movie); }
        }

        public MovieListItem AddMovie(Movie movie)
        {
            int index = 0;
            if (OrderSelector == null) index = listView.Items.Count;
            else
            {
                foreach (MovieListItem m in listView.Items)
                {
                    if (OrderSelector(m.Movie).CompareTo(OrderSelector(movie)) >= 0) break;
                    index++;
                }
            }
            var item = new MovieListItem(movie);
            listView.Items.Insert(index, item);
            return item;
        }

        public void Clear()
        {
            listView.Items.Clear();
        }

        public void RemoveMovie(Movie movie)
        {
            var toRemove = new List<MovieListItem>();
            foreach (MovieListItem li in listView.Items)
            {
                if (li.Movie == movie)
                {
                    toRemove.Add(li);
                }
            }
            foreach (var listItem in toRemove)
            {
                listView.Items.Remove(listItem);
            }
        }

        public void RemoveItem(MovieListItem item)
        {
            listView.Items.Remove(item);
        }

        public Func<Movie, IComparable> OrderSelector
        {
            get { return orderSelector; }
            set 
            {
                orderSelector = value;
                var movies = listView.Items.Cast<Movie>();
                if (value != null) movies = movies.OrderBy(value);
                var moviesList = movies.ToList();
                listView.Items.Clear();
                foreach (var m in moviesList)
                {
                    listView.Items.Add(m);
                }
            }
        }

        #region Implementation of ISearchAcceptor

        public SearchQuery CurrentSearch { get; set; }

        #endregion

        /*
        void MovieUpdated(object sender, ItemUpdatedEventArgs<MovieItem<Movie>> e)
        {
            bool inList = false;
            foreach (MovieListItem item in listView.Items)
            {
                if (item.Movie.Id == e.UpdatedItem.Id)
                {
                    if (CurrentSearch != null && !item.Movie.Matches(CurrentSearch))
                    {
                        listView.Items.Remove(item);
                    }
                    else
                    {
                        item.SetFields();
                        inList = true;
                    }
                    break;
                }
            }
            if (!inList && CurrentSearch != null && !e.UpdatedItem.Matches(CurrentSearch))
            {
                AddMovie((Movie)e.UpdatedItem);
            }
        }*/
    }
}
